Microsoft Fastfile Package Format
Archived from http://www.cinnamonpirate.com/docs/fastfile on 2006/2/7
Grudgingly copied and pasted from his browser by D

I encountered Fastfile packages in 2001, for the first time, while trying to hack Falcom’s Ys Eternal. The game included a data.ys file that was an unknown package. After coming up with an extractor, a mysterious FFCREATE.EXE came out along with all the graphics.

FFCREATE.EXE was a Fastfile creator made by Microsoft for the DirectX 5.0 SDK. I believe this file was originally distributed as source, along with a FASTFILE.H include file for accessing Fastfile packages as a file system. If you’re interested in Microsoft’s code, get your hands on an old MSDN disk.

The question new programmers may ask is, why on Earth would you want to cram all your resources into one file? Simple: I/O lag.

There are four key reasons to use a package file when making a game. By having a package file with all resource, only one file handle is needed for the game. This file handle can be left open at all times, which offers a speed boost on NTFS system which suffer from a lag in CreateFile() calls due to checking security. Package files also conserve disk space. Individual files will always suck up the minimum cluster size on the hard disk, which can waste 10 - 15 percent of your disk space on even a FAT32 disk: on NTFS it wastes even more. OS file systems are also slower than the file system of a package file because they are designed to search, read, write, rename, append and delete. Games generally only need to be able to read, except for writing save files. Lastly, the data can be organized in the order it’s called to speed up the access of frequently used files.

In today’s world of 4GHz processors, these may not be common concerns for developers. In the days of DirectX 5.0, however, the average user had 90MHz of power under their hood; lag and load times were serious problems.

The Fastfile structure is extremely simple, all values are stored in little endian order:

File count + 1 [4 bytes, long]
(file loop)
  File offset [4 bytes, long]
  File name [12 bytes, string (DOS 8.3 filename)]
(end loop)
End offset [4 bytes, long]
(data)

The data section is nothing but the contents of all files copied together in the order listed in the header.

Below is a short proof of concept that will extract all the contents of a Fastfile to a series of files:

$fd = fopen('result.ff', 'rb');
list($junk, $count) = unpack('l*', fread($fd, 4));
$offset = array();
$filename = array();
for($i=0; $i< $count-1; $i++) {
  list($junk, $offset[$i]) = unpack('l*', fread($fd, 4));
  $filename[$i] = rtrim(fread($fd, 13));
}
list($junk, $offset[$i]) = unpack('l*', fread($fd, 4));
for($i=0; $i<$count-1; $i++) {
  $fo = fopen($filename[$i], 'w');
  fseek($fd, $offset[$i], SEEK_SET);
  fputs($fo, fread($fd, ($offset[($i+1)]-$offset[$i])));
  fclose($fo);
}
fclose($fd);